(SST) ShlWAPI.pas Version 1.08

Developer Reference
(SST)ShlWAPI MLLoadLibrary Function
Loads a Multilingual User Interface (MUI), resource dll associated with an executable code dll.
Scope
Global (i.e. this function can be called/accessed from code in any unit that includes/uses (SST)ShlWAPI.pas).
Syntax
function MLLoadLibrary(lpLibFileName : LPCSTR; moduleh : HMODULE; dwCrossCodePage : DWORD) : HMODULE;
Parameters
lpLibFileName [in] The file name of the Multilingual User Interface (MUI), resource dll to load, in form of a zero-terminated string. This string should be resticted to the name of the file only (i.e. it should not inclide a relative or fully qualifed path to the file).
moduleh [in] A handle to the dll containing the executable code for which the resource dll is to be loaded. This parameter may be 0.
dwCrossCodePage [in] Reserved, should be set to 0, but see remarks, below.
Symbolic Name Value Description*1
ML_NO_CROSSCODEPAGE 0 Symbolic name/constant that, according to the Ms SDK 6.1 documentation, represents the only valid value for this parameter.
ML_CROSSCODEPAGE_NT 1 Undocumented by Microsoft at the time this function description was authored.
ML_CROSSCODEPAGE 2 Undocumented by Microsoft at the time this function description was authored.
ML_SHELL_LANGUAGE 4 Undocumented by Microsoft at the time this function description was authored.
ML_CROSSCODEPAGE_MASK 7 Undocumented by Microsoft at the time this function description was authored.
Return Values
If the function was able to locate and load the specified MUI, resource dll, it returns a handle to the dll loaded. If the function fails the return value is 0.
Remarks
The function was documented with parameters differing significantly from the above declaration in the documentation accompanying MS SDK Version 6.0. The declaration in that documentation containing five parameters as opposed to the three of the declaration in Ms SDK 6.0A and later. However, as tests, using the version with 5 parameters, resulted in stack faults, the above is a ported version of the declaration in MS SDK Version 6.0A.
Although the documentation accompanying Ms SDK 6.1 states that the third paramenter ("dwCrossCodePage") is reserved for future use and should therefore always be set to zero (0), the header file of the same SDK defined 5 constants that are obviously flags, related to this parameter.
In spite of the comprehensive and detailed description (in the documentation accompanying Ms SDK 6.1 and later), the purpose and practical use of this function remain unclear, as it does not load the multilungual user interface, resource dll for all code dlls, as is demonstrated in the output of the code example, below. In this example the mui, resource dll assoiated with ComDlg32.dll (ComDlg32.dll.mui), which was correctly installed and present on the system, ought to have been loaded in at least one of the last five calls. However, this was not the case.
Microsoft emphasizes that modules loaded by this function (MLLoadLibrary) should always be freed using MLFreeLibrary (which see), never by means of FreeLibrary.
This function is exported by name as of ShlWAPI.dll version 6.0 under Windows Vista, but according to the documentation it is supported as of ShlWAPI.dll 5.0 under all Windows operating systems (including the 9x series) with IE 5.0 and later. However, this is incompatible with the declaration of the function prototype in ShlWAPI.h of Ms SDK 6.1, which requires at least Windows 2000, and the fact that no ordinal by which the function can be accessed under pre-Vista systems was documented up to (and including) the developer reference accompanying Ms SDK 6.1.
MLLoadLibraryA is exported as ordinal 377, MLLoadLibraryW as ordinal 378. Although not officially documented, both functions can be imported by means of these ordinals, beginning with at least Windows NT 4.0 with IE 5.0 and Windows 98 SE. They remain accessible by these ordinals up to and including Windows 10.
In light of the fact that MLFreeLibrary may no longer be supported under Windows 10 (which remains to be clarified), we recommend not to use this function and instead resort to a lengthier approach, using the National Language Support (NLS) functions and/or LoadLibraryEx.
Example
PROCEDURE TForm4.TestShlWAPIMLLoadLibrary(Sender : TObject); //See doc. on function in Ms SDK version 6.0 and revise function declaration !!! VAR loadedcodedllname : STRING; VAR resdllname : STRING; VAR loadedcodedllh : HMODULE; VAR crosscodepg : DWORD; //VAR resmoduleh : HMODULE; VAR resmodulefilename : ARRAY[0 .. 259] OF CHAR; VAR bufsize : DWORD; VAR newinfoline : STRING; BEGIN //ShowMessage('MLLoadLibrary'); loadedcodedllname := ''; resdllname := ''; loadedcodedllh := 0; crosscodepg := 0; //resmoduleh := 0; bufsize := 0; bufsize := Length(resmodulefilename); FillChar(resmodulefilename, bufsize, #0); newinfoline := ''; loadedcodedllname := 'Shell32.dll'; loadedcodedllh := GetModuleHandle(PChar(loadedcodedllname)); resdllname := loadedcodedllname; newinfoline := 'MLLoadLibrary called with ' + resdllname + ' and mddule handle 0x' + IntToHex(loadedcodedllh, 8) + ' for ' + loadedcodedllname + ' returned : '; Memo1.Lines.Add(newinfoline); //fmlresmoduleh := MLLoadLibrary('Shell32.dll', loadedcodedllh, crosscodepg); fmlresmoduleh := MLLoadLibrary(PChar(resdllname), loadedcodedllh, crosscodepg); newinfoline := 'fmlresmoduleh = 0x' + IntToHex(fmlresmoduleh, 8) + ' (' + IntToStr(fmlresmoduleh) + ') '; IF (fmlresmoduleh <> 0) AND (fmlresmoduleh <> INVALID_HANDLE_VALUE) THEN BEGIN GetModuleFileName(fmlresmoduleh, resmodulefilename, bufsize); newinfoline := newinfoline + ' ("' + resmodulefilename + '")'; Memo1.Lines.Add(newinfoline); TestShlWAPIMLFreeLibrary(Sender); END ELSE Memo1.Lines.Add(newinfoline); loadedcodedllname := 'MMX32.dll'; loadedcodedllh := GetModuleHandle(PChar(loadedcodedllname)); resdllname := loadedcodedllname + '.mui'; newinfoline := 'MLLoadLibrary called with ' + resdllname + ' and mddule handle 0x' + IntToHex(loadedcodedllh, 8) + ' for ' + loadedcodedllname + ' returned : '; Memo1.Lines.Add(newinfoline); //fmlresmoduleh := MLLoadLibrary('MMX32.dll.mui', loadedcodedllh, crosscodepg); fmlresmoduleh := MLLoadLibrary(PChar(resdllname), loadedcodedllh, crosscodepg); newinfoline := 'fmlresmoduleh = 0x' + IntToHex(fmlresmoduleh, 8) + ' (' + IntToStr(fmlresmoduleh) + ') '; IF (fmlresmoduleh <> 0) AND (fmlresmoduleh <> INVALID_HANDLE_VALUE) THEN BEGIN GetModuleFileName(fmlresmoduleh, resmodulefilename, bufsize); newinfoline := newinfoline + ' ("' + resmodulefilename + '")'; Memo1.Lines.Add(newinfoline); TestShlWAPIMLFreeLibrary(Sender); END ELSE Memo1.Lines.Add(newinfoline); loadedcodedllname := 'moricons.dll'; loadedcodedllh := GetModuleHandle(PChar(loadedcodedllname)); resdllname := loadedcodedllname; newinfoline := 'MLLoadLibrary called with ' + resdllname + ' and mddule handle 0x' + IntToHex(loadedcodedllh, 8) + ' for ' + loadedcodedllname + ' returned : '; Memo1.Lines.Add(newinfoline); //fmlresmoduleh := MLLoadLibrary('moricons.dll', loadedcodedllh, crosscodepg); fmlresmoduleh := MLLoadLibrary(PChar(resdllname), loadedcodedllh, crosscodepg); newinfoline := 'fmlresmoduleh = 0x' + IntToHex(fmlresmoduleh, 8) + ' (' + IntToStr(fmlresmoduleh) + ') '; IF (fmlresmoduleh <> 0) AND (fmlresmoduleh <> INVALID_HANDLE_VALUE) THEN BEGIN GetModuleFileName(fmlresmoduleh, resmodulefilename, bufsize); newinfoline := newinfoline + ' ("' + resmodulefilename + '")'; Memo1.Lines.Add(newinfoline); TestShlWAPIMLFreeLibrary(Sender); END ELSE Memo1.Lines.Add(newinfoline); loadedcodedllname := 'IEFrame.dll'; loadedcodedllh := GetModuleHandle(PChar(loadedcodedllname)); resdllname := loadedcodedllname; newinfoline := 'MLLoadLibrary called with ' + resdllname + ' and mddule handle 0x' + IntToHex(loadedcodedllh, 8) + ' for ' + loadedcodedllname + ' returned : '; Memo1.Lines.Add(newinfoline); //fmlresmoduleh := MLLoadLibrary('IEFrame.dll', loadedcodedllh, crosscodepg); fmlresmoduleh := MLLoadLibrary(PChar(resdllname), loadedcodedllh, crosscodepg); newinfoline := 'fmlresmoduleh = 0x' + IntToHex(fmlresmoduleh, 8) + ' (' + IntToStr(fmlresmoduleh) + ') '; IF (fmlresmoduleh <> 0) AND (fmlresmoduleh <> INVALID_HANDLE_VALUE) THEN BEGIN GetModuleFileName(fmlresmoduleh, resmodulefilename, bufsize); newinfoline := newinfoline + ' ("' + resmodulefilename + '")'; Memo1.Lines.Add(newinfoline); TestShlWAPIMLFreeLibrary(Sender); END ELSE Memo1.Lines.Add(newinfoline); loadedcodedllname := 'comdlg32.dll'; loadedcodedllh := GetModuleHandle(PChar(loadedcodedllname)); resdllname := 'NIL'; newinfoline := 'MLLoadLibrary called with ' + resdllname + ' and mddule handle 0x' + IntToHex(loadedcodedllh, 8) + ' for ' + loadedcodedllname + ' returned : '; Memo1.Lines.Add(newinfoline); fmlresmoduleh := MLLoadLibrary(NIL, loadedcodedllh, crosscodepg); //fmlresmoduleh := MLLoadLibrary('', loadedcodedllh, crosscodepg); //Produces the same result as the previous line !!! newinfoline := 'fmlresmoduleh = 0x' + IntToHex(fmlresmoduleh, 8) + ' (' + IntToStr(fmlresmoduleh) + ') '; IF (fmlresmoduleh <> 0) AND (fmlresmoduleh <> INVALID_HANDLE_VALUE) THEN BEGIN GetModuleFileName(fmlresmoduleh, resmodulefilename, bufsize); newinfoline := newinfoline + ' ("' + resmodulefilename + '")'; Memo1.Lines.Add(newinfoline); TestShlWAPIMLFreeLibrary(Sender); END ELSE Memo1.Lines.Add(newinfoline); loadedcodedllname := 'comdlg32.dll'; loadedcodedllh := 0; resdllname := loadedcodedllname; newinfoline := 'MLLoadLibrary called with ' + resdllname + ' and mddule handle 0x' + IntToHex(loadedcodedllh, 8) + ' for ' + loadedcodedllname + ' returned : '; Memo1.Lines.Add(newinfoline); //fmlresmoduleh := MLLoadLibrary('comdlg32.dll', loadedcodedllh, crosscodepg); fmlresmoduleh := MLLoadLibrary(PChar(resdllname), loadedcodedllh, crosscodepg); newinfoline := 'fmlresmoduleh = 0x' + IntToHex(fmlresmoduleh, 8) + ' (' + IntToStr(fmlresmoduleh) + ') '; IF (fmlresmoduleh <> 0) AND (fmlresmoduleh <> INVALID_HANDLE_VALUE) THEN BEGIN GetModuleFileName(fmlresmoduleh, resmodulefilename, bufsize); newinfoline := newinfoline + ' ("' + resmodulefilename + '")'; Memo1.Lines.Add(newinfoline); TestShlWAPIMLFreeLibrary(Sender); END ELSE Memo1.Lines.Add(newinfoline); loadedcodedllname := 'comdlg32.dll'; loadedcodedllh := GetModuleHandle(PChar(loadedcodedllname)); resdllname := loadedcodedllname; newinfoline := 'MLLoadLibrary called with ' + resdllname + ' and module handle 0x' + IntToHex(loadedcodedllh, 8) + ' for ' + loadedcodedllname + ' returned : '; Memo1.Lines.Add(newinfoline); //fmlresmoduleh := MLLoadLibrary('comdlg32.dll', loadedcodedllh, crosscodepg); fmlresmoduleh := MLLoadLibrary(PChar(resdllname), loadedcodedllh, crosscodepg); newinfoline := 'fmlresmoduleh = 0x' + IntToHex(fmlresmoduleh, 8) + ' (' + IntToStr(fmlresmoduleh) + ') '; IF (fmlresmoduleh <> 0) AND (fmlresmoduleh <> INVALID_HANDLE_VALUE) THEN BEGIN GetModuleFileName(fmlresmoduleh, resmodulefilename, bufsize); newinfoline := newinfoline + ' ("' + resmodulefilename + '")'; Memo1.Lines.Add(newinfoline); TestShlWAPIMLFreeLibrary(Sender); END ELSE Memo1.Lines.Add(newinfoline); loadedcodedllname := 'comdlg32.dll'; loadedcodedllh := 0; resdllname := loadedcodedllname + '.mui'; newinfoline := 'MLLoadLibrary called with ' + resdllname + ' and mddule handle 0x' + IntToHex(loadedcodedllh, 8) + ' for ' + loadedcodedllname + ' returned : '; Memo1.Lines.Add(newinfoline); //fmlresmoduleh := MLLoadLibrary('comdlg32.dll.mui', loadedcodedllh, crosscodepg); fmlresmoduleh := MLLoadLibrary(PChar(resdllname), loadedcodedllh, crosscodepg); newinfoline := 'fmlresmoduleh = 0x' + IntToHex(fmlresmoduleh, 8) + ' (' + IntToStr(fmlresmoduleh) + ') '; IF (fmlresmoduleh <> 0) AND (fmlresmoduleh <> INVALID_HANDLE_VALUE) THEN BEGIN GetModuleFileName(fmlresmoduleh, resmodulefilename, bufsize); newinfoline := newinfoline + ' ("' + resmodulefilename + '")'; Memo1.Lines.Add(newinfoline); TestShlWAPIMLFreeLibrary(Sender); END ELSE Memo1.Lines.Add(newinfoline); loadedcodedllname := 'comdlg32.dll'; loadedcodedllh := GetModuleHandle(PChar(loadedcodedllname)); resdllname := loadedcodedllname + '.mui'; newinfoline := 'MLLoadLibrary called with ' + resdllname + ' and module handle 0x' + IntToHex(loadedcodedllh, 8) + ' for ' + loadedcodedllname + ' returned : '; Memo1.Lines.Add(newinfoline); //fmlresmoduleh := MLLoadLibrary('comdlg32.dll.mui', loadedcodedllh, crosscodepg); fmlresmoduleh := MLLoadLibrary(PChar(resdllname), loadedcodedllh, crosscodepg); newinfoline := 'fmlresmoduleh = 0x' + IntToHex(fmlresmoduleh, 8) + ' (' + IntToStr(fmlresmoduleh) + ') '; IF (fmlresmoduleh <> 0) AND (fmlresmoduleh <> INVALID_HANDLE_VALUE) THEN BEGIN GetModuleFileName(fmlresmoduleh, resmodulefilename, bufsize); newinfoline := newinfoline + ' ("' + resmodulefilename + '")'; Memo1.Lines.Add(newinfoline); TestShlWAPIMLFreeLibrary(Sender); END ELSE Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); END;
On NT based systems that support this function, the above code ought to produce an output comparable to that shown below.
MLLoadLibrary called with Shell32.dll and mddule handle 0x75C10000 for Shell32.dll returned : fmlresmoduleh = 0x75C10000 (1975582720) ("C:\Windows\system32\SHELL32.dll") MLFreeLibrary called with fmlresmoduleh = 0x75C10000 (1975582720) returned TRUE MLLoadLibrary called with MMX32.dll.mui and mddule handle 0x00000000 for MMX32.dll returned : fmlresmoduleh = 0x00000000 (0) MLLoadLibrary called with moricons.dll and mddule handle 0x00000000 for moricons.dll returned : fmlresmoduleh = 0x63D50000 (1674903552) ("C:\Windows\system32\moricons.dll") MLFreeLibrary called with fmlresmoduleh = 0x63D50000 (1674903552) returned TRUE MLLoadLibrary called with IEFrame.dll and mddule handle 0x00000000 for IEFrame.dll returned : fmlresmoduleh = 0x6B9E0000 (1805516800) ("C:\Windows\system32\IEFrame.dll") MLFreeLibrary called with fmlresmoduleh = 0x6B9E0000 (1805516800) returned TRUE MLLoadLibrary called with NIL and mddule handle 0x75920000 for comdlg32.dll returned : fmlresmoduleh = 0x00000000 (0) MLLoadLibrary called with comdlg32.dll and mddule handle 0x00000000 for comdlg32.dll returned : fmlresmoduleh = 0x75920000 (1972502528) ("C:\Windows\system32\comdlg32.dll") MLFreeLibrary called with fmlresmoduleh = 0x75920000 (1972502528) returned TRUE MLLoadLibrary called with comdlg32.dll and module handle 0x75920000 for comdlg32.dll returned : fmlresmoduleh = 0x75920000 (1972502528) ("C:\Windows\system32\comdlg32.dll") MLFreeLibrary called with fmlresmoduleh = 0x75920000 (1972502528) returned TRUE MLLoadLibrary called with comdlg32.dll.mui and mddule handle 0x00000000 for comdlg32.dll returned : fmlresmoduleh = 0x00000000 (0) MLLoadLibrary called with comdlg32.dll.mui and module handle 0x75920000 for comdlg32.dll returned : fmlresmoduleh = 0x00000000 (0)
Requirements
Unit: Declared and imported in (SST)ShlWAPI.pas
Library: (SST)ShlWAPI.dcu/(SST)ShlWAPI.obj
Unicode: Implemented as ANSI (MLLoadLibrary and MLLoadLibraryA) and Unicode (MLLoadLibraryW) functions.
Min. ShlWAPI.dll version according to MS SDK doc.: 5.0
Min. ShlWAPI.dll version based on SST research: 5.0
Min. OS version(s) according to Microsoft SDK doc.: Windows NT 4.0 with Internet Explorer 5, Windows 98, Windows 95 with Internet Explorer 5
Min. OS version(s) according to SST research.: Windows NT 4.0 with Internet Explorer 5.0, Windows 98 SE, Windows 2000
See Also
MLFreeLibrary, MLWinHelp
 
Windows APIs: MLLoadLibrary, MLFreeLibrary, MLWinHelp


Document/Contents version 1.00
Page/URI last updated on 07.12.2023
 
Copyright © Stoelzel Software Technologie (SST) 2010 - 2017
Suggestions and comments mail to:
webmaster@stoelzelsoftwaretech.com